﻿using FFmpeg.AutoGen;
using FFmpegLib;
using MediaLib.Interface;
using Silk.NET.OpenAL;
using System;
using System.Threading;

namespace MediaLib.Implement;

public unsafe class SilkSdlAudioPlayer : IAudioPlayer
{

    #region OpenAL obj
    //SilkOpenALUtils _openAL;
    private BufferFormat target_fmt;
    private AVSampleFormat out_sample_fmt;
    #endregion

    private CancellationTokenSource _cancelSource;

    public SourceState CurCtlStatus { get; set; }
    public string AudioFile { get; private set; }
    public int Size { get; private set; }
    public long Bitrate { get; private set; }
    public int ChannelNum { get; private set; }
    public int DepthBit { get; private set; }
    public int PerSampleSize { get; private set; }
    public int SampleRate { get; private set; }
    public FAVStream AudioStreamInfo { get; private set; }
    private FAudioFifo Fifo;
    private FSwrContext SwrCtx;
    private FAVFormatContext InFmtCtx;

    public SilkSdlAudioPlayer()
    {
        throw new NotImplementedException();
    }

    public void AdjustSpeed(float vol)
    {
        throw new NotImplementedException();
    }

    public void AdjustVolume(float vol)
    {
        throw new NotImplementedException();
    }

    public void GetAudioInfo(string audioFile, out long bitrate, out int sampleRate, out int channelNum, out int depthBit, out int size)
    {
        throw new NotImplementedException();
    }

    public void Pause(bool pause)
    {
        throw new NotImplementedException();
    }

    public void Play(string audioFile = null)
    {
        throw new NotImplementedException();
    }

    public void Stop()
    {
        throw new NotImplementedException();
    }

    #region FFmpeg.AutoGen

    /// <summary>
    /// 通过ffmpeg加载音频块
    /// </summary>
    /// <param name="packet"></param>
    /// <param name="frame"></param>
    /// <returns>采样数</returns>
    /// <exception cref="ArgumentException"></exception>
    private void LoadByFFmpeg(FAVPacket packet, FAVFrame frame)
    {
        if (InFmtCtx == null || !InFmtCtx.FmtCtxIsOpen)
            return;

        int ret = InFmtCtx.ReadPacket(packet);
        if (ret < 0 || packet.StreamIndex != InFmtCtx.AudioIndex)
            return;

        ret = InFmtCtx.Decode(packet, frame);
        if (ret < 0)
            return;

        frame.TimeBase = InFmtCtx.AudioStream.TimeBase;

        if (target_fmt == 0)
        {
            SampleRate = frame.SampleRate;
            ChannelNum = frame.Channels;
            (AVSampleFormat avFmt, BufferFormat alFmt) = SilkOpenALUtils.AVSampleFmtToALFmt(frame.AudioFormat, frame.Channels);
            target_fmt = alFmt;
            out_sample_fmt = avFmt;
            PerSampleSize = ffmpeg.av_get_bytes_per_sample(out_sample_fmt);
            Fifo ??= new FAudioFifo(out_sample_fmt, ChannelNum);

            SwrCtx ??= new FSwrContext(frame, out_sample_fmt);
            if (SwrCtx.Inited == false)
                return;

        }

        if (Fifo == null)
            throw new ArgumentException("AudioDecodeUtil->_fifo初始化异常");

        PcmFrame pcm = null;
        try
        {
            pcm = SwrCtx.ConvertAudioPcmData(frame, out_sample_fmt);
            if (pcm.NbSamples > 0)
                Fifo.Enqueue(pcm.Pcm, pcm.NbSamples);
        }
        finally { pcm?.Dispose(); }
        return;
    }


    #endregion

    #region Dispose
    private bool disposedValue;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                // TODO: 释放托管状态(托管对象)
            }

            // TODO: 释放未托管的资源(未托管的对象)并重写终结器
            // TODO: 将大型字段设置为 null
            disposedValue = true;
        }
    }

    // // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器
    // ~SilkSdlAudioPlayer()
    // {
    //     // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
    //     Dispose(disposing: false);
    // }

    public void Dispose()
    {
        // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }
    #endregion

    #region SDL

    public void Play()
    {
        throw new NotImplementedException();
    }

    #endregion
}